"""
Helpers to keep Neo4j in sync with Django knowledge nodes.
"""

from __future__ import annotations

import logging
from typing import Iterable

from django.conf import settings
from neo4j.exceptions import Neo4jError

from config.neo4j_client import get_neo4j_driver

logger = logging.getLogger("pioneer_xiaoke")

NODE_LABEL = "KnowledgeNode"
REL_TYPE = "REQUIRES"


def _neo4j_enabled() -> bool:
    return bool(settings.NEO4J_URI and settings.NEO4J_PASSWORD)


def sync_knowledge_node(node):
    """
    Upsert a Neo4j node mirror for the provided Django instance.
    """
    if not _neo4j_enabled():
        return

    driver = get_neo4j_driver()
    payload = {
        "id": node.id,
        "user_id": node.user_id,
        "name": node.name,
        "node_type": node.node_type,
        "mastery_level": node.mastery_level,
        "difficulty_level": node.difficulty_level,
        "description": node.description or "",
    }

    query = f"""
    MERGE (n:{NODE_LABEL} {{django_id: $id}})
    SET n.name = $name,
        n.user_id = $user_id,
        n.node_type = $node_type,
        n.mastery_level = $mastery_level,
        n.difficulty_level = $difficulty_level,
        n.description = $description
    """

    try:
        with driver.session() as session:
            session.execute_write(lambda tx: tx.run(query, **payload))
    except Neo4jError as exc:
        logger.error("Failed to sync Neo4j node: %s", exc)


def sync_prerequisites(node, prerequisites: Iterable[int]):
    """
    Replace prerequisite relationships for the given node.
    """
    if not _neo4j_enabled():
        return

    driver = get_neo4j_driver()
    prereq_ids = list(prerequisites)
    if prereq_ids:
        from .models import KnowledgeNode  # Local import to avoid circular dependency

        for pre_node in KnowledgeNode.objects.filter(id__in=prereq_ids):
            sync_knowledge_node(pre_node)

    def _replace_relationships(tx):
        tx.run(
            f"""
            MATCH (n:{NODE_LABEL} {{django_id: $node_id}})-[r:{REL_TYPE}]->(:{NODE_LABEL})
            DELETE r
            """,
            node_id=node.id,
        )
        if not prereq_ids:
            return
        tx.run(
            f"""
            MATCH (n:{NODE_LABEL} {{django_id: $node_id}})
            UNWIND $prereq_ids AS prereq_id
            MATCH (pre:{NODE_LABEL} {{django_id: prereq_id}})
            MERGE (n)-[:{REL_TYPE}]->(pre)
            """,
            node_id=node.id,
            prereq_ids=prereq_ids,
        )

    try:
        with driver.session() as session:
            session.execute_write(_replace_relationships)
    except Neo4jError as exc:
        logger.error("Failed to sync Neo4j relationships: %s", exc)


def delete_knowledge_node(node_id: int):
    """
    Remove a node (and its relationships) from Neo4j when deleted in Django.
    """
    if not _neo4j_enabled():
        return

    driver = get_neo4j_driver()
    try:
        with driver.session() as session:
            session.execute_write(
                lambda tx: tx.run(
                    f"""
                    MATCH (n:{NODE_LABEL} {{django_id: $node_id}})
                    DETACH DELETE n
                    """,
                    node_id=node_id,
                )
            )
    except Neo4jError as exc:
        logger.error("Failed to delete Neo4j node: %s", exc)
